package com.weir.member.oauth;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.UriBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;

/**
 * Shows how to create a simple OAuth integration.
 *
 * To Use:
 *
 * export CLIENT_ID=XXX
 * export CLIENT_SECRET=XXX
 * mvn compile quarkus:dev
 *
 *
 * in browser navigate to http://6545-117-173-226-142.ngrok.io/oauth/login
 */
@Path("/oauth-github")
public class GithubOauthResource {

    public static class GithubAuthReq {

        @JsonProperty("client_id")
        public final String clientId;

        @JsonProperty("client_secret")
        public final String clientSecret;

        @JsonProperty("redirect_url")
        public final String redirectUrl = "http://fee0-117-173-226-142.ngrok.io/oauth";

        @JsonProperty("scope")
        public final String scope = "read:user read:org";

        @JsonProperty("state")
        public final String state = UUID.randomUUID().toString();

        @JsonProperty("allow_signup")
        public final String allowSignup = "false";

        public GithubAuthReq(String clientId, String clientSecret) {
            this.clientId = clientId;
            this.clientSecret = clientSecret;
        }

        public URI getAuthorizeUri() {
            return UriBuilder.fromUri("https://github.com/login/oauth/authorize")
                    .queryParam("client_id", clientId)
                    .queryParam("redirect_url", redirectUrl)
                    .queryParam("scope", scope)
                    .queryParam("state", state)
                    .queryParam("allow_signup", allowSignup)
                    .build();
        }

        public URI getCodeUri(String code) {
            return UriBuilder.fromUri("https://github.com/login/oauth/access_token")
                    .queryParam("client_id", clientId)
                    .queryParam("client_secret", clientSecret)
                    .queryParam("redirect_url", redirectUrl)
                    .queryParam("code", code)
                    .queryParam("state", state)
                    .build();
        }

    }

    private Client client = ResteasyClientBuilder.newClient();
    private Map<String, GithubAuthReq> outstandingRequests = new HashMap<>();
    private Map<String, String> accessTokens = new HashMap<>();

    @Context HttpServletRequest request;

    @Path("/home")
    @Produces(MediaType.APPLICATION_JSON)
    @GET
    public Response home() {
        Cookie sessionCookie = null;
        for (Cookie cookie : request.getCookies()) {
            if (cookie.getName().equals("session")) {
                sessionCookie = cookie;
            }
        }
        if (sessionCookie == null) {
            return Response.seeOther(UriBuilder.fromPath("/oauth/login").build()).build();
        }

        String token = accessTokens.get(sessionCookie.getValue());
        final String bearer = "token " + token;
        final String teamsJson = client.target("https://api.github.com/user").request().header("Authorization", bearer).get().readEntity(String.class);
        final String orgsJson = client.target("https://api.github.com/user/orgs").request().header("Authorization", bearer).get().readEntity(String.class);
        return Response.ok()
                .entity("{\"teams\":" + teamsJson + ",\"orgs\":" + orgsJson + "}")
                .build();
        /**
         * {
    "teams": {
        "login": "weir2010",
        "id": 404015,
        "node_id": "MDQ6VXNlcjQwNDAxNQ==",
        "avatar_url": "https://avatars.githubusercontent.com/u/404015?v=4",
        "gravatar_id": "",
        "url": "https://api.github.com/users/weir2010",
        "html_url": "https://github.com/weir2010",
        "followers_url": "https://api.github.com/users/weir2010/followers",
        "following_url": "https://api.github.com/users/weir2010/following{/other_user}",
        "gists_url": "https://api.github.com/users/weir2010/gists{/gist_id}",
        "starred_url": "https://api.github.com/users/weir2010/starred{/owner}{/repo}",
        "subscriptions_url": "https://api.github.com/users/weir2010/subscriptions",
        "organizations_url": "https://api.github.com/users/weir2010/orgs",
        "repos_url": "https://api.github.com/users/weir2010/repos",
        "events_url": "https://api.github.com/users/weir2010/events{/privacy}",
        "received_events_url": "https://api.github.com/users/weir2010/received_events",
        "type": "User",
        "site_admin": false,
        "name": "weir",
        "company": null,
        "blog": "http://www.loveweir.com/",
        "location": null,
        "email": null,
        "hireable": null,
        "bio": "关注架构设计",
        "twitter_username": null,
        "public_repos": 150,
        "public_gists": 0,
        "followers": 5,
        "following": 77,
        "created_at": "2010-09-17T05:59:09Z",
        "updated_at": "2021-11-08T04:05:41Z",
        "private_gists": 0,
        "total_private_repos": 0,
        "owned_private_repos": 0,
        "disk_usage": 224,
        "collaborators": 0,
        "two_factor_authentication": false,
        "plan": {
            "name": "free",
            "space": 976562499,
            "collaborators": 0,
            "private_repos": 10000
        }
    },
    "orgs": []
}
         */
    }

    @GET
    @Path("/callback")
    public Response callback() {
        String state = request.getParameter("state");
        String code = request.getParameter("code");
        GithubAuthReq req = outstandingRequests.remove(state);
        if (req == null || !req.state.equals(state)) {
        	return Response.status(Status.BAD_REQUEST).entity("not accepted").build();
        }
        
        WebTarget target = this.client.target(req.getCodeUri(code));
        Response response = target.request().get();
        if (response.getStatus() != 200) {
            return Response.status(Status.BAD_REQUEST).entity("not accepted by github").build();
        }
        
        InputStream inputStream = (InputStream) response.getEntity();
        String result = new BufferedReader(new InputStreamReader(inputStream))
        		  .lines().collect(Collectors.joining("\n"));
        System.out.println("result----------->" + result);
        
        /**
         * 以 & 为分割字符分割 result
         */
        String[] githubResultList = result.split("&");
        List<String> params = new ArrayList<>();
        // paramMap 是分割后得到的参数对, 比说 access_token=ad5f4as6gfads4as98fg
        for (String paramMap : githubResultList) {
            if (!"scope".equals(paramMap.split("=")[0])){
                // 再以 = 为分割字符分割, 并加到 params 中
                params.add(paramMap.split("=")[1]);
            }
        }
        
        final String sessionId = UUID.randomUUID().toString();
        accessTokens.put(sessionId, params.get(0));
        return Response.seeOther(UriBuilder.fromPath("/oauth/home").build())
                .cookie(new NewCookie("session", sessionId))
                .build();
    }

    @GET
    @Path("/login")
    @Produces(MediaType.TEXT_HTML)
    public Response login() {
    	String getenv = "f2bb003d1642d62b8cf5";
    	String getenv2 = "71578d24b32522062d275ae928e37820757d0b8e";
        GithubAuthReq req = new GithubAuthReq(getenv, getenv2);
        outstandingRequests.put(req.state, req);
        return Response
                .ok(String.format("<body><a href='%s'>click to login with github</a></body>", req.getAuthorizeUri()))
                .build();
    }
    
    @GET
    public String name() {
		return "hello";
	}
}